package easier.recycler;

import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import easier.recycler.MultiTypeAdapter.MultiTypeHolder;
import java.util.List;

/**
 * 生成指定类型的界面,并且在{@link ViewHolder}不断复用过程中,绑定数据到界面
 */
public abstract class TypeViewHolder {

    /**
     * 此处绑定数据,推荐实现这个方法
     *
     * @param viewHolder recycler 的ViewHolder
     * @param root       item 根布局
     * @param position   布局位置adapterPosition
     * @param type       类型
     * @param payloads   数据变化
     */
    protected void onBind( ViewHolder viewHolder, View root, int position, int type, @NonNull List< Object > payloads ) {}

    /**
     * @param viewHolder 此处解绑数据
     */
    protected void onUnBind( ViewHolder viewHolder, View root, int position ) {}

    /**
     * {@link MultiTypeAdapter#onViewDetachedFromWindow(MultiTypeHolder)}处通知界面不可见了
     */
    protected void onDetachedFromWindow( ViewHolder viewHolder, View root ) {}

    /**
     * {@link MultiTypeAdapter#onViewAttachedToWindow(MultiTypeHolder)}处通知界面可见
     */
    protected void onAttachedToWindow( ViewHolder viewHolder, View root ) {}

    /**
     * 通过位于{@link RecyclerView}下的一个子界面的View,获取{@link ViewHolder}
     * 因为adapter可以和许多recycler绑定,只能通过此方法获取绑定的ViewHolder
     *
     * @return 获取当前与数据绑定的ViewHolder, 如果为null, 那么没有viewHolder绑定
     */
    @Nullable
    public ViewHolder getViewHolder( RecyclerView recyclerView, View view ) {

        try {
            return recyclerView.getChildViewHolder( view );
        } catch ( Exception e ) {

            ViewParent current = view.getParent();
            ViewParent next = current.getParent();

            do {
                if ( next == recyclerView ) {
                    if ( current instanceof View ) {
                        return recyclerView.getChildViewHolder( (View) current );
                    } else {
                        return null;
                    }
                }

                current = next;
                next = next.getParent();

            } while ( next != null );

            return null;
        }
    }

    /**
     * @return adapter position
     */
    public int getPosition( RecyclerView recyclerView, View view ) {

        ViewHolder viewHolder = getViewHolder( recyclerView, view );
        if ( viewHolder != null ) {
            return viewHolder.getAdapterPosition();
        } else {
            return RecyclerView.NO_POSITION;
        }
    }

    /**
     * @return 获取绑定的根布局
     */
    @Nullable
    public View getRootView( RecyclerView recyclerView, View view ) {

        ViewHolder viewHolder = getViewHolder( recyclerView, view );
        if ( viewHolder != null ) {
            return viewHolder.itemView;
        } else {
            return null;
        }
    }

    /**
     * 工具方法获取该ViewHolder下的view
     *
     * @param recyclerView viewHolder 对应的 recyclerView
     * @param view         该viewHolder里的一个View,用于找到根布局
     * @param id           view的ID
     * @param <T>          找到的对应ID的view,可能为null
     *
     * @return 找到的对应ID的view, 可能为null
     */
    public < T extends View > T findViewById( RecyclerView recyclerView, View view, @IdRes int id ) {

        View rootView = getRootView( recyclerView, view );
        if ( rootView != null ) {
            return rootView.findViewById( id );
        }
        return null;
    }

    /**
     * 生成{@link #getType()} 关联的布局,
     *
     * @param parent 父布局
     *
     * @return 布局, 该布局不会关联到onBind方法中
     */
    public abstract View generateView( ViewGroup parent );

    /**
     * @param view 回调方法,在View创建后回调,可以再此处初始化界面,注意和{@link #onBind(ViewHolder, View, int, int, List)}
     *             区别,此处只有View创建后回调一次,{@link #onBind(ViewHolder, View, int, int, List)}每次{@link MultiTypeAdapter#onBindViewHolder(MultiTypeHolder, int)}
     *             都会回调
     */
    protected void onViewCreate( View view ) {}

    /**
     * 界面数据类型
     *
     * @return 类型
     */
    public abstract int getType();

    /**
     * 更新该root所在{@link ViewHolder}界面数据
     *
     * @param recyclerView recycler
     * @param child        该recycler下的一个子view
     */
    public void notifyItemChanged( RecyclerView recyclerView, View child ) {

        notifyItemChanged( recyclerView, child, 0 );
    }

    /**
     * 更新该root所在{@link ViewHolder}界面数据
     *
     * @param recyclerView recycler
     * @param child        该recycler下的一个子view
     * @param payload      更新数据
     */
    public void notifyItemChanged( RecyclerView recyclerView, View child, Object payload ) {

        notifyItemChanged( recyclerView, child, 0, payload );
    }

    /**
     * {@link #notifyItemChanged(RecyclerView, View)}增加了一个偏移量
     */
    public void notifyItemChanged( RecyclerView recyclerView, View child, int offset ) {

        int position = getPosition( recyclerView, child );
        notifyItemChanged( recyclerView, position + offset );
    }

    /**
     * {@link #notifyItemChanged(RecyclerView, View)}增加了一个偏移量
     */
    public void notifyItemChanged( RecyclerView recyclerView, View child, int offset, @Nullable Object payload ) {

        int position = getPosition( recyclerView, child );
        notifyItemChanged( recyclerView, position + offset, payload );
    }

    /**
     * @param recyclerView recycler
     * @param position     位置
     */
    public void notifyItemChanged( RecyclerView recyclerView, int position ) {

        notifyItemChanged( recyclerView, position, 0 );
    }

    /**
     * @param recyclerView recycler
     * @param position     位置
     * @param payload      数据变化
     */
    public void notifyItemChanged( RecyclerView recyclerView, int position, @Nullable Object payload ) {

        notifyItemChanged( recyclerView, position, 0, payload );
    }

    /**
     * @param recyclerView recycler
     * @param position     位置
     * @param offset       偏移量
     */
    public void notifyItemChanged( RecyclerView recyclerView, int position, int offset ) {

        notifyItemChanged( recyclerView, position, offset, null );
    }

    /**
     * @param recyclerView recycler
     * @param position     位置
     * @param offset       偏移量
     * @param payload      数据变化
     */
    public void notifyItemChanged( RecyclerView recyclerView, int position, int offset, @Nullable Object payload ) {

        if ( position >= 0 ) {
            Adapter< ? > adapter = recyclerView.getAdapter();
            if ( adapter != null ) {
                adapter.notifyItemChanged( position + offset, payload );
            }
        }
    }

    /**
     * {@link MultiTypeAdapter#updateViewHolders(List)}判断两个布局是否一样
     *
     * @param obj 比较项
     *
     * @return true:一样
     */
    public boolean itemEquals( @NonNull TypeViewHolder obj ) {

        return false;
    }

    /**
     * {@link MultiTypeAdapter#updateViewHolders(List)}判断两个布局内容是否一样
     *
     * @param obj 比较项
     *
     * @return true:一样
     */
    public boolean contentEquals( @NonNull TypeViewHolder obj ) {

        return false;
    }
}
